import { Component, Vec2, Rect, rect, v2, assetManager, Asset, misc, game, director, sys, UITransform, Node, Vec3, v3 } from "cc";
import { Group, Tween, TWEEN } from "./Tween";

/**
 * 工具类
 */
export default class Tools {
    /**
     * 深拷贝
     * @param source 源数据
     */
    public static deepCopy<T>(source: T): T {
        if (typeof source !== "object" || source === null || source instanceof RegExp) {
            return source;
        }

        let result: any = null;
        if (Array.isArray(source)) {
            result = [];
            for (let item of source) {
                result.push(this.deepCopy(item));
            }
        } else {
            result = {};
            for (let key in source) {
                result[key] = this.deepCopy(source[key]);
            }
        }

        return result;
    }

    /**
     * 异步等待 - setTimeout
     * @param seconds 
     */
    public static wait(seconds: number): Promise<void> {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve();
            }, seconds * 1000);
        });
    }

    /**
     * 
     * @param delay - 延迟时长 [单位：s]
     * @param call - 延迟会掉
     */
    public static delay(delay: number, call: (...args: any) => any) {
        if (Number.isNaN(delay) || delay <= 0) {
            try {
                call();
            } catch (e) {
                console.warn('Tool delay debug!!!', e);
            }
        } else if (Number.isFinite(delay)) {
            let id = setTimeout(() => {
                clearTimeout(id);
                try {
                    call();
                } catch (e) {
                    console.warn('Tool delay debug!!!', e);
                }
            }, delay * 1000);
        }
    }

    /**
     * 异步等待 - Component.scheduleOnce
     */
    public static waitCmpt(cmpt: Component, seconds: number): Promise<void> {
        return new Promise((resolve, reject) => {
            cmpt.scheduleOnce(() => {
                resolve();
            }, seconds);
        });
    }

    /**
     * 异步等待 - tween 默认group为TWEEN
     */
    public static waitTween(cmpt: Component, seconds: number, group: Group = TWEEN): Promise<void> {
        return new Promise((resolve, reject) => {
            new Tween({ k: 0 }, group)
                .to({ k: 1 }, seconds * 1000)
                .onComplete(() => {
                    resolve();
                })
                .start()
                .bindCCObject(cmpt);
        });
    }

    /**
     * 线性插值
     * @param a 起始值
     * @param b 目标值
     * @param r ratio between 0 and 1
     * @param min 最小间隔值
     */
    public static lerp(a: number, b: number, r: number, min: number = 0): number {
        min = Math.abs(min);
        let c = b - a;
        let delta = c * r;
        delta = delta < 0 ? Math.min(delta, -min) : Math.max(delta, min);
        if (Math.abs(delta) > Math.abs(c)) {
            delta = c;
        }
        return a + delta;
    }

    /**
     * 通过两点坐标(不平行于坐标轴)和x，计算两点式方程结果y
     */
    public static calcTwoPointForm(p1: Vec2, p2: Vec2, x: number): number {
        if (p1.x === p2.x) return p1.y;
        return (p2.y - p1.y) * (x - p1.x) / (p2.x - p1.x) + p1.y;
    }

    /**
     * 返回两个矩形的重叠矩形，不重叠则返回null
     */
    public static overlapRect(r1: Rect, r2: Rect): Rect {
        let xMin = Math.max(r1.xMin, r2.xMin);
        let xMax = Math.min(r1.xMax, r2.xMax);
        let yMin = Math.max(r1.yMin, r2.yMin);
        let yMax = Math.min(r1.yMax, r2.yMax);

        if (xMin > xMax || yMin > yMax) {
            return null;
        }
        return rect(xMin, yMin, xMax - xMin, yMax - yMin);
    }

    /**
     * 返回value是否在 [min, max] 区间内
     * @param min 
     * @param max 
     * @param value
     * @param includeEdge true(默认值): [min, max]; false: (min, max)
     */
    public static inRange(min: number, max: number, value: number, includeEdge: boolean = true): boolean {
        return includeEdge ? value >= min && value <= max : value > min && value < max;
    }

    /**
     * 获取区间[min, max)的整数，传入1个参数则区间为[0, min)
     */
    public static randInt(min: number, max: number = undefined): number {
        if (max === undefined) {
            max = min;
            min = 0;
        }
        min = Math.ceil(min);
        max = Math.floor(max);
        return Math.floor(Math.random() * (max - min)) + min;
    }

    /**
     * 获取区间[min, max)的浮点数，传入1个参数则区间为[0, min)
     */
    public static randFloat(min: number, max: number = undefined): number {
        if (max === undefined) {
            max = min;
            min = 0;
        }
        return Math.random() * (max - min) + min;
    }

    /**
     * Fisher–Yates shuffle 字符串随机乱序
     */
    public static shuffleString(str: string): string {
        let arr: string[] = [];
        for (let i = 0; i < str.length; i++) {
            arr.push(str[i]);
        }
        arr = this.shuffle(arr);
        str = "";
        arr.forEach((v) => {
            str += v;
        });
        return str;
    }

    /**
     * 子节点递归处理
     * @param node 需要递归处理的节点或节点数组
     * @param cb 节点处理函数
     * @param thisArg cb绑定的this对象
     */
    public static nodeRecursive(node: Node | Node[], cb: (n: Node) => void, thisArg: any = undefined): void {
        if (node instanceof Node) {
            cb.call(thisArg, node);
            node.children.forEach((n: Node) => { this.nodeRecursive(n, cb, thisArg); });
        } else if (Array.isArray(node)) {
            node.forEach((n: Node) => { this.nodeRecursive(n, cb, thisArg); });
        }
    }

    /**
     * destroy并立即remove传入节点的所有子节点
     */
    public static clearChildren(...nodes: Node[]): void {
        nodes.forEach((e) => {
            e.destroyAllChildren();
            e.removeAllChildren();
        });
    }

    /**
     * 保留x位小数
     * @param targetNum 需要转换的数字
     * @param decimal 保留几位小数
     * @returns 保留x位的number
     */
    public static numberToFixed(targetNum: number, decimal: number) {
        return Number(targetNum.toFixed(decimal));
    }

    /**
    * 获取A相对B的局部坐标
    * @param {*} nodeA 
    * @param {*} nodeB 
    */
    public static getNodeAToNodeBPoint(nodeA: Node, nodeB: Node) {

        var nodeAWorldPoint = nodeA.getComponent(UITransform).convertToWorldSpaceAR(Vec3.ZERO);
        //console.log("nodeAWorldPoint",nodeAWorldPoint);
        var AToBPos = nodeB.getComponent(UITransform).convertToNodeSpaceAR(nodeAWorldPoint);

        return v3(AToBPos.x, AToBPos.y, 1) //{ x: AToBPos.x, y: AToBPos.y };
    }

    /**
 * 获取A点相对B节点的局部坐标
 * @param posA A点的局部坐标（相对于A的父节点）
 * @param parentA A的父节点
 * @param nodeB B节点
 */
    public static getPosAToNodeBPoint(posA: Vec3, parentA: Node, nodeB: Node): Vec3 {
        // 先将 A 点的局部坐标转换为世界坐标
        const posAWorld = parentA.getComponent(UITransform)?.convertToWorldSpaceAR(posA);

        // 将世界坐标转换为相对于 B 节点的局部坐标
        if (posAWorld) {
            const AToBPos = nodeB.getComponent(UITransform)?.convertToNodeSpaceAR(posAWorld);
            // 返回 Vec3 类型的坐标，如果 AToBPos 可能为 undefined，需要额外处理
            if (AToBPos) {
                return v3(AToBPos.x, AToBPos.y, posA.z); // 保留 Z 坐标值
            }
        }

        // 防止返回空值
        return v3(0, 0, 0);
    }

    /**
     * 获取节点在目标节点（容器）下的相对位置
     * @param node 节点
     * @param container 目标节点（容器）
     * @param nodepos 已有node节点坐标可传
     */
    public static getRelativePosition(node: Node, container: Node, nodepos?: Vec3,): Vec3 {
        const worldPos = (node.getParent() || node).getComponent(UITransform).convertToWorldSpaceAR(nodepos ? nodepos : node.getPosition());
        return container.getComponent(UITransform).convertToNodeSpaceAR(worldPos);
    }

    /**
    * 坐标是否在目标节点范围内
    * @param pos 坐标
    * @param target 目标节点
    */
    public static isPosOnNodeRect(pos: Vec2, target: Node): boolean {
        const rect = target.getComponent(UITransform).getBoundingBoxToWorld();
        return rect.contains(pos);
    }

    /**
     * 两个节点是否重叠
     * @param node1 节点 1
     * @param node2 节点 2
     * @param contains 是否完全包含
     */
    public static areNodesOverlap(node1: Node, node2: Node, contains: boolean = false): boolean {
        const rect1 = node1.getComponent(UITransform).getBoundingBoxToWorld(),
            rect2 = node2.getComponent(UITransform).getBoundingBoxToWorld();
        return contains ? rect1.containsRect(rect2) : rect1.intersects(rect2);
    }


    /**查找节点*/
    public static GetChildByName(obj, name, bRecursive) {
        let node = obj.node ? obj.node : obj;
        let child = null;
        if (node && name) {
            child = node.getChildByName(name);
            if (bRecursive) {
                if (!child) {
                    let children = node.children;
                    let childrenCount = node.childrenCount;
                    for (let i = 0; i < childrenCount; ++i) {
                        child = this.GetChildByName(children[i], name, bRecursive);
                        if (child) {
                            break;
                        }
                    }
                }
            }
        }
        return child;
    }

    //获取以目标点为圆心某个半径上的位置 R半径 angle:角度
    public static getPosByRot(R: number, angle: number): Vec2 {
        var x = R * Math.cos(2 * Math.PI / 360 * (90 - angle))
        var y = R * Math.sin(2 * Math.PI / 360 * (90 - angle))
        return v2(x, y)
    }

    //加载远程资源
    public static loadRemoteAsset(url: string) {
        return new Promise((resolve, reject) => {
            assetManager.loadRemote(url, (e, res: Asset) => {
                if (e) {
                    console.log(`加载远程资源错误url:${url}`, e)
                    reject(e);
                    return;
                }
                resolve(res)
            })
        })
    }
    //加载远程图片
    public static loadRemoteImg(url: string) {
        return new Promise((resolve, reject) => {
            assetManager.loadRemote(url, { ext: '.png' }, (e, res: Asset) => {
                if (e) {
                    console.log(`加载远程图片资源错误url:${url}`, e)
                    reject(e);
                    return;
                }
                resolve(res)
            })
        })
    }

    /** 生成n个[min, max)之间的不重复的随机整数 */
    public static randomsInt(min: number, max: number, n: number) {
        if (n > max - min) {
            n = max - min;
        }
        let arr: number[] = Array.from({ length: max - min }, (v, k) => k + min);// arr = [min, max];
        for (let i = 0; i < n; i++) {// 洗牌算法(随机乱置算法), 仅打乱[0, n);
            let j = Math.floor(Math.random() * (arr.length - i) + i);// j = [i, arr.length)之间的随机整数
            [arr[i], arr[j]] = [arr[j], arr[i]];
        }
        arr.length = n;// 取前n项
        return arr;
    }

    /**
    * 将弧度转换为角度, 0 ~ 360
    */
    public static RadiansToDegrees(radians) {
        return misc.radiansToDegrees(radians);// 2.x
        // return radiansToDegrees(radians);// 1.x
    }

    /**
    * 将角度转换为弧度
    */
    public static DegreesToRadians(degrees) {
        return misc.degreesToRadians(degrees);// 2.x
        // return degreesToRadians(degrees);// 1.x
    }

    /**
    * 彻底暂停游戏，包含渲染，音频和事件
    */
    public static PauseGame() {
        game.pause();
    }

    public static ResumeGame() {
        game.resume();
    }

    public static IsPausedGame() {
        return game.isPaused();
    }

    /**
    * 暂停正在运行的场景，该暂停只会停止游戏逻辑执行，但是不会停止渲染和 UI 响应
    */
    public static PauseDirector() {
        director.pause();
    }

    public static ResumeDirector() {
        director.resume();
    }

    public static IsPausedDirector() {
        return director.isPaused();
    }

    /**
    * 设置游戏帧率
    */
    public static SetFrameRate(newRate) {
        game.setFrameRate(newRate);
    }

    /**
    * 退出游戏
    */
    public static ExitGame() {
        if (sys.isBrowser) {
            window.history.back();
            window.close();
        } else {
            game.end();
        }
    }
    /////////////////////////////////////////////////////////////数组操作////////////////////////////////////////////////////////////////////////////////////

    //  判断数组一致性
    public static arraysEqual(arr1: number[][], arr2: number[][]): boolean {
        if (arr1.length !== arr2.length) return false;
        for (let i = 0; i < arr1.length; i++) {
            if (arr1[i].length !== arr2[i].length) return false;
            for (let j = 0; j < arr1[i].length; j++) {
                if (arr1[i][j] !== arr2[i][j]) return false;
            }
        }
        return true;
    }

    /**
    * 根据权重数组进行随机，返回结果下标
    * @param weightArr 权重数组
    * @returns 随机到的权重数组下标
    */
    public static randWeightIdx(weightArr: number[]) {
        let sum = 0;
        for (let i = 0; i < weightArr.length; i++) {
            sum += weightArr[i];
        }
        let randNum = this.randFloat(0, sum);
        let curValue = 0
        for (let i = 0; i < weightArr.length; i++) {
            curValue += weightArr[i];
            if (randNum < curValue) {
                return i;
            }
        }
        return weightArr.length - 1;
    }

    /**
     * 随机返回数组中的一个元素
     */
    public static arrayRand<T>(arr: Array<T>): T {
        if (arr.length <= 0) {
            return null;
        }
        return arr[this.randInt(0, arr.length)];
    }

    /**
     * 二维数组旋转
     * @param matrix 二维矩阵
     * @param clockwise 是否顺时针
     * @returns 
     */
    public static rotateMatrix(matrix: any[][], clockwise: boolean = true): any[][] {
        const rowCount = matrix.length;
        const colCount = matrix.reduce((max, row) => Math.max(max, row.length), 0); // 找到最长行的长度
        const rotatedMatrix: any[][] = Array.from({ length: colCount }, () => Array(rowCount).fill(null)); 

        for (let i = 0; i < rowCount; i++) {
            for (let j = 0; j < matrix[i].length; j++) {
                if (clockwise) {
                    rotatedMatrix[j][rowCount - 1 - i] = matrix[i][j];
                } else {
                    rotatedMatrix[colCount - 1 - j][i] = matrix[i][j];
                }
            }
        }

        return rotatedMatrix;
    }


    /**
     * 返回一个新数组，新数组包含 arr 中索引为 0 到 length 的元素
     * @param arr 原数组
     * @param length 新数组长度
     * @returns 
     */
    public static getSubArray(arr: any[], length: number): any[] {
        return arr.slice(0, length);
    }

    /**
     * 判断数组中是否有某个元素
     * @param arr 数组
     * @param param 元素值或表达元素值满足某种条件的函数
     */
    public static arrayHas<T>(arr: T[], param: T | ((ele: T) => boolean)): boolean {
        let idx = typeof param !== "function" ? arr.findIndex((e) => { return e === param; }) : arr.findIndex(param as ((ele: T) => boolean));
        return idx >= 0;
    }

    /**
     * 根据下标交换数组两个元素位置
     */
    public static arraySwap<T>(arr: T[], idx1: number, idx2: number): void {
        if (idx1 === idx2 || !this.inRange(0, arr.length - 1, idx1) || !this.inRange(0, arr.length - 1, idx2)) {
            return;
        }
        [arr[idx1], arr[idx2]] = [arr[idx2], arr[idx1]];
    }

    /**
     * 将元素从fromIdx位置移到toIdx位置，其余元素相对位置不变
     */
    public static arrayMove<T>(arr: T[], fromIdx: number, toIdx: number): void {
        if (fromIdx === toIdx || !this.inRange(0, arr.length - 1, fromIdx) || !this.inRange(0, arr.length - 1, toIdx)) {
            return;
        }
        let from: T[] = arr.splice(fromIdx, 1);
        arr.splice(toIdx, 0, from[0]);
    }

    /**
     * 在数组中添加某个元素
     * @param canRepeat 是否可重复添加相同元素 默认false
     * @return 是否执行了添加行为
     */
    public static arrayAdd<T>(arr: T[], ele: T, canRepeat: boolean = false): boolean {
        if (!canRepeat && this.arrayHas(arr, ele)) {
            return false;
        }
        arr.push(ele);
        return true;
    }

    /**
     * 在数组中删除某个元素(若有多个相同元素则只删除第一个)
     * @return 是否执行了删除行为
     */
    public static arrayDelete<T>(arr: T[], ele: T): boolean {
        let index: number = arr.findIndex((e) => { return e === ele; });
        if (index >= 0) {
            arr.splice(index, 1);
            return true;
        } else {
            return false;
        }
    }

    /**
    * Fisher–Yates shuffle 数组随机乱序
    */
    public static shuffle<T>(arr: Array<T>): Array<T> {
        for (let i = arr.length - 1; i >= 0; i--) {
            let randomIndex = Math.floor(Math.random() * (i + 1));
            [arr[randomIndex], arr[i]] = [arr[i], arr[randomIndex]];
        }
        return arr;
    }
    /**打乱数组顺序 */
    public static shuffle1(arr) {
        let i: number = arr.length;
        while (i) {
            let j: number = Math.floor(Math.random() * i--);
            [arr[j], arr[i]] = [arr[i], arr[j]];
        }
        return arr;
    }

    /** 数组去重 */
    public static arrayDeduplication(arr) {
        const removeDuplicates = list => [...new Set(list)];
        return removeDuplicates(arr);
    }

    /**
     * 创建一个0-n的数组
     * @param n 数组0-n长度
     * @returns 
     */
    public static generateArray(n: number): number[] {
        const createArr = (n: number) => Array.from(new Array(n), (v, i) => i);
        return createArr(n);
    }

    /**
     * 多数组取交集
     * @param args 多个数组参数arr1,arr2,arr3...
     * @returns 交集数组
     */
    public static intersectionOfMultipleArrays(...args: any[]): any[] {
        /**
         * 计算多个数组的交集
         * @param a 第一个数组
         * @param arr 剩余的数组
         * @returns 交集数组
         */
        const intersection = (a: any[], ...arr: any[]): any[] => {
            return [...new Set(a)].filter((v) => arr.every((b) => b.includes(v)));
        };
        return intersection.apply(null, args);
    }

    /**
     * 查找数组中最小值索引
     * @param arr 
     * @returns 
     */
    public static findTheMinimumIndex(arr) {
        const indexOfMin = (arr) => arr.reduce((prev, curr, i, a) => (curr < a[prev] ? i : prev), 0);
        return indexOfMin(arr);
    }

    /**
     * 找到最接近的数值
     * @param arr 数字数组
     * @param value 对比值
     */
    public static findTheClosestValue(arr, value) {
        const closest = (arr, n) => arr.reduce((prev, curr) => (Math.abs(curr - n) < Math.abs(prev - n) ? curr : prev));
        closest(arr, value);
    }

    /**
    * 压缩多个数组
    * @param args 多个数组参数 arr1, arr2, arr3...
    * @returns 压缩的数组
    */
    public static compressMultipleArrays(...args: any[]): any[] {
        /**
         * 将多个数组进行压缩
         * @param arr 多个数组
         * @returns 压缩后的数组
         */
        const zip = (...arr: any[]): any[] => {
            return Array.from(
                { length: Math.max(...arr.map((a) => a.length)) },
                (_, i) => arr.map((a) => a[i])
            );
        };

        return zip(...args);
    }
    /**
    * 矩阵交换行和列
    * @param matrixArr 矩阵数组
    * @returns 交换行和列后的矩阵数组
    */
    public static matrixSwappingRowsAndColumns(matrixArr: any[][]): any[][] {
        /**
         * 转置矩阵，交换行和列
         * @param matrix 矩阵数组
         * @returns 交换行和列后的矩阵数组
         */
        const transpose = (matrix: any[][]): any[][] => {
            return matrix[0].map((col, i) => matrix.map((row) => row[i]));
        };

        return transpose(matrixArr);
    }

    /////////////////////////////////////////////////////////////数字转换////////////////////////////////////////////////////////////////////////////////////

    /**
     * 将 10 进制转换成 n 进制
     * @param number 10进制数字
     * @param baseN n进制
     * @returns 
     */
    public static convertBase10ToBaseN(number, baseN) {
        const toDecimal = (num, n = 10) => num.toString(n)
        // 数字number要转换成baseN进制
        return toDecimal(number, baseN)
    }

    /**
    * 将 n 进制转换成 10 进制
    * @param number n 进制数字
    * @param base n 进制数的基数，默认为 10
    * @returns 转换后的 10 进制数字
    */
    public static convertBaseNToBase10(number: string, base = 10): number {
        /**
         * 将 n 进制数字转换成 10 进制数字
         * @param num n 进制数字
         * @param n n 进制数的基数，默认为 10
         * @returns 转换后的 10 进制数字
         */
        const toDecimalism = (num: string, n: number = 10): number => {
            return parseInt(num, n);
        };

        // 将 n 进制数字转换成 10 进制
        return toDecimalism(number, base);
    }

    /**
     * 手机号格式化 xxx-xxxx-xxxx 
     * @param phoneNum 手机号
     * @param delimiter 间隔符好 默认'-'
     */
    public static phoneNumberFormatting(phoneNum, delimiter = '-') {
        const formatPhone = (str, sign = '-') => str.replace(/(\W|\s)/g, "").split(/^(\d{3})(\d{4})(\d{4})$/).filter(item => item).join(sign);
        formatPhone(phoneNum, delimiter);
    }

    /**
    * 截断数字，将小数点后的某些数字截断而不取四舍五入
    * @param n 要截断的数字
    * @param fixed 要保留的小数位数
    * @returns 截断后的数字字符串
    */
    public static truncateNumber(n: number, fixed: number): string {
        const truncated = `${n}`.match(new RegExp(`^-?\\d+(?:\\.\\d{0,${fixed}})?`));
        return truncated ? truncated[0] : '';
    }

    /**
     * 四舍五入数字，将小数点后的某些数字截断，并进行四舍五入
     * @param n 要四舍五入的数字
     * @param decimals 要保留的小数位数
     * @returns 四舍五入后的数字
     */
    public static roundNumber(n: number, decimals: number = 0): number {
        const multiplier = 10 ** decimals;
        return Math.round(n * multiplier) / multiplier;
    }

    /**
     * 补零操作，当数字不足指定位数时在前面补零
     * @param num 要补零的数字
     * @param len 补零后的总位数
     * @param zero 补零时使用的字符，默认为 0
     * @returns 补零后的字符串
     */
    public static padZero(num: number, len: number, zero: string = '0'): string {
        return num.toString().padStart(len, zero);
    }

    /////////////////////////////////////////////////////////////日期////////////////////////////////////////////////////////////////////////////////////

    /**
    * 判断日期是否为今天
    * @param date 要判断的日期
    * @returns 如果日期是今天则返回 true，否则返回 false
    */
    public static checkIfTheDateIsToday(date: Date): boolean {
        /**
         * 检查日期是否为今天
         * @param d 要检查的日期
         * @returns 如果日期是今天则返回 true，否则返回 false
         */
        const isToday = (d: Date): boolean => {
            const today = new Date();
            return (
                d.getFullYear() === today.getFullYear() &&
                d.getMonth() === today.getMonth() &&
                d.getDate() === today.getDate()
            );
        };

        // 判断日期是否为今天
        return isToday(date);
    }

    /**
     * 日期转换为为 YYYY-MM-DD 格式
     * @param date 要判断的日期
     * @returns YYYY-MM-DD 格式的日期
     */
    public static dateConversion(date: Date) {
        const formatYmd = (date) => date.toISOString().slice(0, 10);
        return formatYmd(date);
    }

    /**
     * 秒数转换为 hh:mm:ss 格式
     * @param seconds 秒数
     * @returns hh:mm:ss 格式
     */
    public static secondsConversion(seconds) {
        const formatSeconds = (s) => new Date(s * 1000).toISOString().substr(11, 8);
        return formatSeconds(seconds);
    }

    /////////////////////////////////////////////////////////////对象////////////////////////////////////////////////////////////////////////////////////

    /**
    * 删除对象中属性值为 null 或 undefined 的所有属性
    * @param obj 要删除属性的对象
    * @returns 删除属性后的对象
    */
    public static removeNullUndefined(obj: object): object {
        return Object.entries(obj).reduce((a, [k, v]) => (v == null ? a : ((a[k] = v), a)), {});
    }

    /**
     * 反转对象的键值对
     * @param obj 要反转的对象
     * @returns 反转后的对象
     */
    public static invertObject(obj: object): object {
        return Object.keys(obj).reduce((res, k) => Object.assign(res, { [obj[k]]: k }), {});
    }

    /**
     * 将字符串转换为对象
     * @param str 要转换的字符串
     * @returns 转换后的对象
     */
    public static parseStringToObject(str: string): object {
        return JSON.parse(str.replace(/(\w+)\s*:/g, (_, p1) => `"${p1}":`).replace(/'/g, '"'));
    }

    /**
    * 比较多个对象是否相等
    * @param objects 多个对象
    * @returns 是否相等
    */
    public static isEqual(...objects: object[]): boolean {
        return objects.every(obj => JSON.stringify(obj) === JSON.stringify(objects[0]));
    }

    /**
     * 生成随机颜色
     * @returns 随机颜色
     */
    public static getRandomColor(): string {
        return `#${Math.floor(Math.random() * 0xffffff).toString(16)}`;
    }

    /**
     * 将16进制颜色转换为RGB格式
     * @param hex 16进制颜色
     * @returns RGB格式颜色数组
     */
    public static hexToRgb(hex: string): number[] {
        return hex.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i, (_, r, g, b) => `#${r}${r}${g}${g}${b}${b}`)
            .substring(1)
            .match(/.{2}/g)
            .map((x) => parseInt(x, 16));
    }

    /**
     * 生成随机IP地址
     * @returns 随机IP地址
     */
    public static randomIp(): string {
        return Array(4)
            .fill(0)
            .map((_, i) => Math.floor(Math.random() * 255) + (i === 0 ? 1 : 0))
            .join('.');
    }

    /**
    * 生成 UUID
    * @param a 参数
    * @returns UUID
    */
    public static uuid(a?: any): string {
        return a
            ? (a ^ ((Math.random() * 16) >> (a / 4))).toString(16)
            : ([1e7] as any[]).concat(-1e3, -4e3, -8e3, -1e11)
                .map((v: number) => v.toString(16))
                .join('')
                .replace(/[018]/g, (c: string) => {
                    const r = (Math.random() * 16) | 0;
                    const v = c === "0" ? r : (r & 0x3) | 0x8;
                    return v.toString(16);
                });
    }

    /**
     * 获取Cookie并转换成对象
     * @returns Cookie对象
     */
    public static getCookie(): object {
        return document.cookie
            .split(';')
            .map((item) => item.split('='))
            .reduce((acc, [k, v]) => ((acc[k.trim().replace('"', '')] = v), acc), {});
    }

    /////////////////////////////////////////////////////////////向量////////////////////////////////////////////////////////////////////////////////////

    /**
     * 计算两个向量的差
     * @param vec1 向量1
     * @param vec2 向量2
     * @returns 
     */
    vectorDifference(vec1: Vec3, vec2: Vec3): Vec3 {
        // 使用 cc.Vec3 的 subtract 方法计算向量差
        const result = new Vec3();
        Vec3.subtract(result, vec1, vec2);
        return result;
    }
}
